package com.hup.minicontroller.server.hardware;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.WindowManager;

import androidx.arch.core.util.Function;

import java.lang.reflect.Method;

import static java.lang.Class.forName;

/**
 * 利用SurfaceControl实现截屏;
 * .需要是[系统应用]!! android:sharedUserId="android.uid.system"
 * .SurfaceControl的方法是不向app开放的(即使是public static也不能调用时通过编译)所以要用反射
 * .得到的图像带虚拟按键区域
 * .需要sdk=?
 * .只在特定硬件上应用过,所以某些逻辑是固定的(如屏幕旋转,屏幕默认角度),其他设备使用应该有bug
 * 本类只做记录!
 */
public class ScreenShotUtil {
    private static final String TAG = ScreenShotUtil.class.getSimpleName();

    private Method mScreenShot;

    private WindowManager windowManager;
    private Configuration configuration;
    private Point pSrcSize;
    private DisplayMetrics realMetrics;

    public ScreenShotUtil(Context context) {
        try {
            Class<?> classSurface = forName(SurfaceControl.class.getName());
            mScreenShot = classSurface.getMethod("screenshot", int.class, int.class);
            mScreenShot.setAccessible(true);

            windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            configuration = context.getResources().getConfiguration();
            realMetrics = new DisplayMetrics();
            pSrcSize = new Point();
        } catch (Exception e) {
            Log.e(TAG, "static initializer: 初始化异常", e);
        }
    }

    /**
     * @param function 获取到截图后的回调,回调入参是nullable;
     * 注意function的Bitmap入参会在方法返回后被自动recycle!!
     */
    public <T> T getScreenShot(Function<Bitmap, T> function) {
        if (mScreenShot == null) {
            Log.i(TAG, "getScreenShot: 对象化异常");
            return function.apply(null);
        }

        Bitmap image = null;
        try {
            //要每次更新:处理转屏
            int orientation = configuration.orientation;
            windowManager.getDefaultDisplay().getRealMetrics(realMetrics);
            windowManager.getDefaultDisplay().getSize(pSrcSize);
            /*
            realMetrics的宽高在屏幕旋转后是会变的,所以两个invoke传入的尺寸值是一样的!
            本代码是摘录的,不完整的,如pSrcSize用于其他业务,而算法本身针对的设备默认是横屏的??,所以一般手机不适用??
             */
            int resultWidth = realMetrics.widthPixels;
            int resultHeight = realMetrics.heightPixels;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                //横屏
                image = (Bitmap) mScreenShot.invoke(null, new Object[]{resultWidth, resultHeight});
            } else {
                //竖屏
                image = (Bitmap) mScreenShot.invoke(null, new Object[]{resultHeight, resultWidth});
                //处理屏幕旋转
                if (image != null) {
                    int wid0 = image.getWidth();
                    int hei0 = image.getHeight();
                    Matrix matrix = new Matrix();
                    float scaleWidth = ((float) hei0) / wid0;
                    float scaleHeight = ((float) wid0) / hei0;
                    matrix.postScale(scaleWidth, scaleHeight);
                    Bitmap newBM = Bitmap.createBitmap(image, 0, 0, wid0, hei0, matrix, false);
                    if (newBM != image) { //@see Bitmap.createBitmap()
                        image.recycle();
                        image = newBM;
                    }
                }
            }
            return function.apply(image);
        } catch (ReflectiveOperationException e) {
            Log.e(TAG, "getScreenShot: 反射异常", e);
            return function.apply(null);
        } finally {
            if (image != null) {
                image.recycle();
            }
        }
    }

}
